package cn.usbtg.sutil;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.security.spec.InvalidKeySpecException;

/**
 * 基础加密组件
 * <p/>
 * <pre>
 * BASE64加密解密
 * MD5单项加密
 * SHA单项加密
 * HMAC单项带秘钥加密
 * </pre>
 *
 * @author Zhang Jia ning
 * @version 1.0
 * @date 2015-08-11
 */
public class Encryption {

    public static final String ENCODING_DEFAULT = "UTF-8";
    public static final String ENCODING_UTF8 = "UTF-8";
    public static final String ENCODING_GBK = "GBK";

    // //////////////////////////////////////////////////////////
    // BASE64加密解密
    // //////////////////////////////////////////////////////////

    /**
     * BASE64加密
     *
     * @param data 需要加密的字节数组
     * @return 加密后的字符串
     */
    public static String encryptBASE64ToString(byte[] data) {
        return new BASE64Encoder().encodeBuffer(data).trim();
    }

    /**
     * BASE64加密(采用默认编码UTF-8)
     *
     * @param data 需要加密的字符串
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encryptBASE64ToString(String data) {
        return encryptBASE64ToString(data, ENCODING_UTF8);
    }

    /**
     * BASE64加密(采用默认编码UTF-8)
     *
     * @param data     需要加密的字符串
     * @param encoding 字符编码
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encryptBASE64ToString(String data, String encoding) {
        String result = null;
        try {
            result = encryptBASE64ToString(data.getBytes(encoding));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * BASE64解密
     *
     * @param data 需要解密的加密字符串
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static byte[] decryptBASE64(String data) {
        byte[] result = null;
        try {
            result = new BASE64Decoder().decodeBuffer(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * BASE64解密
     *
     * @param data 需要解密的加密字符串
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptBASE64ToString(String data) {
        String result = null;
        try {
            result = new String(decryptBASE64(data), ENCODING_DEFAULT);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * BASE64解密
     *
     * @param data     需要解密的加密字符串
     * @param encoding 字符编码
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptBASE64ToString(String data, String encoding) {
        String result = null;
        try {
            result = new String(decryptBASE64(data), encoding);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    // //////////////////////////////////////////////////////////
    // MD5加密
    // //////////////////////////////////////////////////////////

    /**
     * MD5加密
     *
     * @param data 需要加密的数据
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encryptMD5(byte[] data) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        md5.update(data);
        return md5.digest();
    }

    /**
     * MD5加密
     *
     * @param data 需要加密的数据
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encryptMD5ToString(byte[] data) {
        return bytesToHexString(encryptMD5(data));
    }

    /**
     * MD5加密
     *
     * @param data 需要加密的数据
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encryptMD5ToString(String data) {
        String result = null;
        try {
            result = encryptMD5ToString(data.getBytes(ENCODING_DEFAULT));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * MD5加密
     *
     * @param data     需要加密的数据
     * @param encoding 需要加密的数据的解析编码
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encryptMD5ToString(String data, String encoding) {
        String result = null;
        try {
            result = encryptMD5ToString(data.getBytes(encoding));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    // //////////////////////////////////////////////////////////
    // SHA加密
    // //////////////////////////////////////////////////////////

    /**
     * SHA加密
     *
     * @param data 需要加密的数据
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encryptSHA(byte[] data) {
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("SHA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        md5.update(data);
        return md5.digest();
    }

    /**
     * SHA加密
     *
     * @param data 需要加密的数据
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encryptSHAToString(byte[] data) {
        return bytesToHexString(encryptSHA(data));
    }

    /**
     * SHA加密
     *
     * @param data 需要加密的数据
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encryptSHAToString(String data) {
        String result = null;
        try {
            result = encryptSHAToString(data.getBytes(ENCODING_DEFAULT));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * SHA加密
     *
     * @param data     需要加密的数据
     * @param encoding 需要加密的数据的解析编码
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encryptSHAToString(String data, String encoding) {
        String result = null;
        try {
            result = encryptSHAToString(data.getBytes(encoding));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    // //////////////////////////////////////////////////////////
    // HMAC带秘钥加密
    // //////////////////////////////////////////////////////////
    /**
     * 获取秘钥，MAC算法可选以下多种算法
     * <p/>
     * <pre>
     * HmacMD5
     * HmacSHA1
     * HmacSHA256
     * HmacSHA384
     * HmacSHA512
     * </pre>
     */
    public static final String HMAC_KEY_MAC_MD5 = "HmacMD5";
    public static final String HMAC_KEY_MAC_SHA1 = "HmacSHA1";
    public static final String HMAC_KEY_MAC_SHA256 = "HmacSHA256";
    public static final String HMAC_KEY_MAC_SHA384 = "HmacSHA384";
    public static final String HMAC_KEY_MAC_SHA512 = "HmacSHA512";

    /**
     * 生成HMAC秘钥
     *
     * @return HMAC秘钥
     * @throws Exception
     */
    public static byte[] generatorHMACKey() {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(HMAC_KEY_MAC_MD5);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom();
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 生成HMAC秘钥
     *
     * @param key 秘钥
     * @return HMAC秘钥
     * @throws Exception
     */
    public static byte[] generatorHMACKey(byte[] key) {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(HMAC_KEY_MAC_MD5);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom(key);
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 生成HMAC秘钥
     *
     * @param kayMac 秘钥算法
     * @return 秘钥字符串
     * @throws Exception
     */
    public static byte[] generatorHMACKey(String kayMac) {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(kayMac);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom();
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 生成HMAC秘钥
     *
     * @param key    秘钥
     * @param kayMac 秘钥算法
     * @return HMAC秘钥
     * @throws Exception
     */
    public static byte[] generatorHMACKey(byte[] key, String kayMac) {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(kayMac);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom(key);
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * HMAC加密(采用默认秘钥算法HmacMD5)
     *
     * @param data 需要加密的数据
     * @param key  秘钥
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encryptHMAC(byte[] data, byte[] key) {
        return encryptHMAC(data, key, HMAC_KEY_MAC_MD5);
    }

    /**
     * HMAC加密(指定秘钥算法)
     *
     * @param data   需要加密的数据
     * @param key    秘钥
     * @param kayMac 秘钥算法
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encryptHMAC(byte[] data, byte[] key, String kayMac) {
        SecretKey secretKey = new SecretKeySpec(key, kayMac);
        Mac mac = null;
        try {
            mac = Mac.getInstance(secretKey.getAlgorithm());
            mac.init(secretKey);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return mac.doFinal(data);
    }

    /**
     * HMAC加密(采用默认秘钥算法HmacMD5)
     *
     * @param data 需要加密的字符串
     * @param key  秘钥算法
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encryptHMACTostring(String data, String key) {
        String result = null;
        try {
            result = bytesToHexString(encryptHMAC(data.getBytes(ENCODING_DEFAULT), key.getBytes(ENCODING_DEFAULT)));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * HMAC加密(指定秘钥算法)
     *
     * @param data   需要加密的字符串
     * @param key    秘钥
     * @param keyMac 秘钥算法
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encryptHMACTostring(String data, String key, String keyMac) {
        return encryptHMACTostring(data, key, keyMac, ENCODING_DEFAULT);
    }

    /**
     * HMAC加密(指定秘钥算法)
     *
     * @param data     需要加密的字符串
     * @param key      秘钥
     * @param keyMac   秘钥算法
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 加密后的字符串
     * @throws Exception
     */
    public static String encryptHMACTostring(String data, String key, String keyMac, String encoding) {
        String result = null;
        try {
            result = bytesToHexString(encryptHMAC(data.getBytes(encoding), key.getBytes(encoding), keyMac));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    // //////////////////////////////////////////////////////////
    // DES加密解密
    // //////////////////////////////////////////////////////////
    public static final String DES_KEY_ALGORITHM = "DES"; // 算法名称

    /**
     * 算法名称/加密模式(共有以下四种工作模式)/填充方式(共有3中填充模式)
     * <p/>
     * <pre>
     * ECB：电子密码本模式
     * CBC：加密分组链接模式
     * CFB：加密反馈模式
     * OFB：输出反馈模式
     * </pre>
     * <pre>
     * NoPadding
     * PKCS5Padding
     * ISO10126Padding
     * </pre>
     */
    // public static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding";
    public static final String DES_CIPHER_ALGORITHM = "DES";

    /**
     * 生成DES秘钥
     *
     * @return DES秘钥
     * @throws Exception
     */
    public static byte[] generatorDESKey() {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(DES_KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom();
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 生成DES秘钥
     *
     * @param key 秘钥
     * @return DES秘钥
     * @throws Exception
     */
    public static byte[] generatorDESKey(byte[] key) {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(DES_KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom(key);
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 根据给定秘钥生成DES加密密钥对象key
     *
     * @param key 密钥字符串
     * @return 密钥对象
     * @throws Exception
     */
    private static SecretKey convertToKey(byte[] key) {
        DESKeySpec desKey = null;
        SecretKeyFactory keyFactory = null;
        SecretKey securekey = null;
        try {
            desKey = new DESKeySpec(key);
            keyFactory = SecretKeyFactory.getInstance(DES_KEY_ALGORITHM);
            securekey = keyFactory.generateSecret(desKey);
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return securekey;
    }

    /**
     * DES加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encryptDES(byte[] data, byte[] key) {
        byte[] result = null;

        Key deskey = convertToKey(key);
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(DES_CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, deskey, new SecureRandom());
            result = cipher.doFinal(data);
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * DES加密
     *
     * @param data     需要加密的字符串
     * @param key      秘钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 加密后的十六进制字符串
     * @throws Exception
     */
    public static String encryptDESToString(String data, String key, String encoding) {
        String result = null;
        try {
            result = bytesToHexString(encryptDES(data.getBytes(encoding), hexStringToBytes(key)));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * DES加密
     *
     * @param data 需要加密的字符串
     * @param key  秘钥
     * @return 加密后的十六进制字符串
     * @throws Exception
     */
    public static String encryptDESToString(String data, String key) {
        return encryptDESToString(data, key, ENCODING_DEFAULT);
    }

    /**
     * DES解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return 解密后的数据
     */
    public static byte[] decryptDES(byte[] data, byte[] key) {
        byte[] result = null;
        Key deskey = convertToKey(key);
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(DES_CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, deskey);
            result = cipher.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * DES解密
     *
     * @param data     需要解密的十六进制字符串
     * @param key      秘钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptDESToString(String data, String key, String encoding) {
        String result = null;
        try {
            result = new String(decryptDES(hexStringToBytes(data), hexStringToBytes(key)), encoding);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * DES解密
     *
     * @param data 需要解密的十六进制字符串
     * @param key  秘钥
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptDESToString(String data, String key) {
        return decryptDESToString(data, key, ENCODING_DEFAULT);
    }

    // //////////////////////////////////////////////////////////
    // 3DES加密解密
    // //////////////////////////////////////////////////////////
    private static final String TDES_KEY_ALGORITHM = "DESede";

    /**
     * 算法名称/加密模式(共有以下四种工作模式)/填充方式(共有3中填充模式)
     * <p/>
     * <pre>
     * ECB：电子密码本模式
     * CBC：加密分组链接模式
     * CFB：加密反馈模式
     * OFB：输出反馈模式
     * </pre>
     * <pre>
     * NoPadding
     * PKCS5Padding
     * ISO10126Padding
     * </pre>
     */
    // public static final String TDES_CIPHER_ALGORITHM = "DESede/CBC/NoPadding";
    public static final String TDES_CIPHER_ALGORITHM = "DESede";

    /**
     * 生成TDES秘钥
     *
     * @return TDES秘钥
     * @throws Exception
     */
    public static byte[] generatorTDESKey() {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(TDES_KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom();
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 生成TDES秘钥
     *
     * @param key 秘钥
     * @return TDES秘钥
     * @throws Exception
     */
    public static byte[] generatorTDESKey(byte[] key) {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(TDES_KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom(key);
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * TDES加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encryptTDES(byte[] data, byte[] key) {
        byte[] result = null;
        SecretKey deskey = new SecretKeySpec(key, TDES_KEY_ALGORITHM);
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(TDES_CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, deskey);
            return cipher.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * TDES加密
     *
     * @param data     需要加密的字符串
     * @param key      秘钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 加密后的十六进制字符串
     * @throws Exception
     */
    public static String encryptTDESToString(String data, String key, String encoding) {
        String result = null;
        try {
            return bytesToHexString(encryptTDES(data.getBytes(encoding), hexStringToBytes(key)));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * TDES加密
     *
     * @param data 需要加密的字符串
     * @param key  秘钥
     * @return 加密后的十六进制字符串
     * @throws Exception
     */
    public static String encryptTDESToString(String data, String key) {
        return encryptTDESToString(data, key, ENCODING_DEFAULT);
    }

    /**
     * TDES解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return 解密后的数据
     * @throws Exception
     */
    public static byte[] decryptTDES(byte[] data, byte[] key) {
        byte[] result = null;
        Key deskey = new SecretKeySpec(key, TDES_KEY_ALGORITHM);
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(TDES_CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, deskey);
            result = cipher.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * TDES解密
     *
     * @param data     需要解密的十六进制字符串
     * @param key      秘钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptTDESToString(String data, String key, String encoding) {
        String result = null;
        try {
            result = new String(decryptTDES(hexStringToBytes(data), hexStringToBytes(key)), encoding);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * TDES解密
     *
     * @param data 需要解密的十六进制字符串
     * @param key  秘钥
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptTDESToString(String data, String key) {
        return decryptTDESToString(data, key, ENCODING_DEFAULT);
    }

    // //////////////////////////////////////////////////////////
    // AES带秘钥加密解密
    // //////////////////////////////////////////////////////////
    private static final String AES_KEY_ALGORITHM = "AES"; // 秘钥加密算法

    /**
     * 算法名称/加密模式(共有以下四种工作模式)/填充方式(共有3中填充模式)
     * <p/>
     * <pre>
     * ECB：电子密码本模式
     * CBC：加密分组链接模式
     * CFB：加密反馈模式
     * OFB：输出反馈模式
     * </pre>
     * <pre>
     * NoPadding
     * PKCS5Padding
     * ISO10126Padding
     * </pre>
     */
    // public static final String AES_CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
    static final String AES_CIPHER_ALGORITHM = "AES";

    /**
     * 生成AES秘钥
     *
     * @return AES秘钥
     * @throws Exception
     */
    public static byte[] generatorAESKey() {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(AES_KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom();
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * 生成AES秘钥
     *
     * @param key 秘钥
     * @return AES秘钥
     * @throws Exception
     */
    public static byte[] generatorAESKey(byte[] key) {
        KeyGenerator kg = null;
        try {
            kg = KeyGenerator.getInstance(AES_KEY_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecureRandom secureRandom = new SecureRandom(key);
        kg.init(secureRandom);
        SecretKey secretKey = kg.generateKey();
        return secretKey.getEncoded();
    }

    /**
     * AES加密
     *
     * @param data 待加密数据
     * @param key  密钥
     * @return 加密后的数据
     * @throws Exception
     */
    public static byte[] encrypt(byte[] data, byte[] key) {
        byte[] result = null;
        SecretKey secretkey = new SecretKeySpec(key, AES_KEY_ALGORITHM);
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretkey);
            result = cipher.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * AES加密
     *
     * @param data     需要加密的字符串
     * @param key      秘钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 加密后的十六进制字符串
     * @throws Exception
     */
    public static String encryptAESToString(String data, String key, String encoding) {
        String result = null;
        try {
            return bytesToHexString(encrypt(data.getBytes(encoding), hexStringToBytes(key)));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * AES加密
     *
     * @param data 需要加密的字符串
     * @param key  秘钥
     * @return 加密后的十六进制字符串
     * @throws Exception
     */
    public static String encryptAESToString(String data, String key) {
        return encryptAESToString(data, key, ENCODING_DEFAULT);
    }

    /**
     * AES解密
     *
     * @param data 待解密数据
     * @param key  密钥
     * @return 解密后的数据
     * @throws Exception
     */
    public static byte[] decrypt(byte[] data, byte[] key) {
        byte[] result = null;
        SecretKey secretkey = new SecretKeySpec(key, AES_KEY_ALGORITHM);
        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance(AES_CIPHER_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretkey);
            result = cipher.doFinal(data);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * AES解密
     *
     * @param data     需要解密的十六进制字符串
     * @param key      秘钥
     * @param encoding 需要加密的数据和秘钥的解析编码
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptAESToString(String data, String key, String encoding) {
        String result = null;
        try {
            result = new String(decrypt(hexStringToBytes(data), hexStringToBytes(key)), encoding);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * AES解密
     *
     * @param data 需要解密的十六进制字符串
     * @param key  秘钥
     * @return 解密后的原始字符串
     * @throws Exception
     */
    public static String decryptAESToString(String data, String key) {
        return decryptAESToString(data, key, ENCODING_DEFAULT);
    }

    // //////////////////////////////////////////////////////////
    // 十六进制转换
    // //////////////////////////////////////////////////////////
    private final static byte[] HEX_BYTES = "0123456789ABCDEF".getBytes();

    /**
     * 将byte[]转换为十六进制进制字符串
     *
     * @param bytes byte数组
     * @return 十六进制进制字符串
     */
    public static String bytesToHexString(byte[] bytes) {
        int l = bytes.length;
        byte[] buff = new byte[2 * l];
        for (int i = 0; i < l; i++) {
            buff[2 * i] = HEX_BYTES[(bytes[i] >> 4) & 0x0f];
            buff[2 * i + 1] = HEX_BYTES[bytes[i] & 0x0f];
        }
        return new String(buff);
    }

    /**
     * 将十六进制进制字符串转换为byte[]
     *
     * @param hexstr byte数组
     * @return 十六进制进制字符串
     */
    public static byte[] hexStringToBytes(String hexstr) {
        byte[] b = new byte[hexstr.length() / 2];
        int k = 0;
        for (int i = 0, l = b.length; i < l; i++) {
            char c0 = hexstr.charAt(k++);
            char c1 = hexstr.charAt(k++);
            b[i] = (byte) ((parse(c0) << 4) | parse(c1));
        }
        return b;
    }

    /**
     * 将字符转换为整数
     *
     * @param c 需要计算的字符
     * @return 计算后的整数
     */
    private static int parse(char c) {
        if (c >= 'a') return (c - 'a' + 10) & 0x0f;
        if (c >= 'A') return (c - 'A' + 10) & 0x0f;
        return (c - '0') & 0x0f;
    }

    // //////////////////////////////////////////////////////////
    // main测试
    // //////////////////////////////////////////////////////////

    /**
     * 测试主方法
     *
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws UnsupportedEncodingException {
        String sourceStr = "hello 世界!";
        byte[] encodeBytes = null;
        String encodeStr = null;
        byte[] decodeBytes = null;
        String decodeStr = null;
        String key = null;

        // 原始数据
        System.out.println("原始数据：\t" + sourceStr);
        System.out.println("----------------------------------------");
        
        /*
         * BASE64加密解密
         */
        // BASE64加密
        encodeStr = encryptBASE64ToString(sourceStr.getBytes(ENCODING_UTF8));
        System.out.println("BASE64加密后1：\t" + encodeStr);
        encodeStr = encryptBASE64ToString(sourceStr);
        System.out.println("BASE64加密后2：\t" + encodeStr);
        encodeStr = encryptBASE64ToString(sourceStr, ENCODING_UTF8);
        System.out.println("BASE64加密后3：\t" + encodeStr);
        // BASE64解密
        decodeStr = new String(decryptBASE64(encodeStr), ENCODING_UTF8);
        System.out.println("BASE64解密后1：\t" + decodeStr);
        decodeStr = decryptBASE64ToString(encodeStr);
        System.out.println("BASE64解密后2：\t" + decodeStr);
        decodeStr = decryptBASE64ToString(encodeStr, ENCODING_UTF8);
        System.out.println("BASE64解密后3：\t" + decodeStr);

        System.out.println("----------------------------------------");
        
        /*
         * MD5加密
         */
        encodeStr = bytesToHexString(encryptMD5(sourceStr.getBytes(ENCODING_UTF8)));
        System.out.println("MD5加密后1：\t" + encodeStr);
        encodeStr = encryptMD5ToString(sourceStr.getBytes(ENCODING_UTF8));
        System.out.println("MD5加密后2：\t" + encodeStr);
        encodeStr = encryptMD5ToString(sourceStr);
        System.out.println("MD5加密后3：\t" + encodeStr);
        encodeStr = encryptMD5ToString(sourceStr, ENCODING_UTF8);
        System.out.println("MD5加密后4：\t" + encodeStr);

        System.out.println("----------------------------------------");
        
        /*
         * SHA加密
         */
        encodeStr = bytesToHexString(encryptSHA(sourceStr.getBytes(ENCODING_UTF8)));
        System.out.println("SHA加密后1：\t" + encodeStr);
        encodeStr = encryptSHAToString(sourceStr.getBytes(ENCODING_UTF8));
        System.out.println("SHA加密后2：\t" + encodeStr);
        encodeStr = encryptSHAToString(sourceStr);
        System.out.println("SHA加密后3：\t" + encodeStr);
        encodeStr = encryptSHAToString(sourceStr, ENCODING_UTF8);
        System.out.println("SHA加密后4：\t" + encodeStr);

        System.out.println("----------------------------------------");
        
        /*
         * HMAC带秘钥加密
         */
        key = bytesToHexString(generatorHMACKey(HMAC_KEY_MAC_MD5));
        System.out.println("HMAC秘钥：\t" + key);

        encodeStr = bytesToHexString(encryptHMAC(sourceStr.getBytes(ENCODING_DEFAULT), key.getBytes(ENCODING_DEFAULT)));
        System.out.println("HMAC后1：\t" + encodeStr);
        encodeStr = bytesToHexString(encryptHMAC(sourceStr.getBytes(ENCODING_DEFAULT), key.getBytes(ENCODING_DEFAULT), HMAC_KEY_MAC_MD5));
        System.out.println("HMAC后2：\t" + encodeStr);
        encodeStr = encryptHMACTostring(sourceStr, key);
        System.out.println("HMAC后3：\t" + encodeStr);
        encodeStr = encryptHMACTostring(sourceStr, key, HMAC_KEY_MAC_MD5);
        System.out.println("HMAC后4：\t" + encodeStr);
        encodeStr = encryptHMACTostring(sourceStr, key, HMAC_KEY_MAC_MD5, ENCODING_UTF8);
        System.out.println("HMAC后5：\t" + encodeStr);
        System.out.println("----------------------------------------");
        
        /*
         * DES带秘钥加密解密
         */
        key = bytesToHexString(generatorDESKey(hexStringToBytes(sourceStr)));
        System.out.println("DES秘钥：\t\t" + key);

        encodeBytes = encryptDES(sourceStr.getBytes(ENCODING_UTF8), hexStringToBytes(key));
        encodeStr = bytesToHexString(encodeBytes);
        System.out.println("DES加密后1：\t" + encodeStr);
        encodeStr = encryptDESToString(sourceStr, key);
        System.out.println("DES加密后2：\t" + encodeStr);
        encodeStr = encryptDESToString(sourceStr, key, ENCODING_UTF8);
        System.out.println("DES加密后3：\t" + encodeStr);

        decodeBytes = decryptDES(hexStringToBytes(encodeStr), hexStringToBytes(key));
        decodeStr = new String(decodeBytes, ENCODING_UTF8);
        System.out.println("DES解密后1：\t" + decodeStr);
        decodeStr = decryptDESToString(encodeStr, key);
        System.out.println("DES解密后2：\t" + decodeStr);
        decodeStr = decryptDESToString(encodeStr, key, ENCODING_UTF8);
        System.out.println("DES解密后3：\t" + decodeStr);
        System.out.println("----------------------------------------");
        
        /*
         * 3DES带秘钥加密解密
         */
        key = bytesToHexString(generatorTDESKey(hexStringToBytes(sourceStr)));
        System.out.println("3DES秘钥：\t" + key);

        encodeBytes = encryptTDES(sourceStr.getBytes(ENCODING_UTF8), hexStringToBytes(key));
        encodeStr = bytesToHexString(encodeBytes);
        System.out.println("3DES加密后1：\t" + encodeStr);
        encodeStr = encryptTDESToString(sourceStr, key);
        System.out.println("3DES加密后2：\t" + encodeStr);
        encodeStr = encryptTDESToString(sourceStr, key, ENCODING_UTF8);
        System.out.println("3DES加密后3：\t" + encodeStr);

        decodeBytes = decryptTDES(hexStringToBytes(encodeStr), hexStringToBytes(key));
        decodeStr = new String(decodeBytes, ENCODING_UTF8);
        System.out.println("3DES解密后1：\t" + decodeStr);
        decodeStr = decryptTDESToString(encodeStr, key);
        System.out.println("3DES解密后2：\t" + decodeStr);
        decodeStr = decryptTDESToString(encodeStr, key, ENCODING_UTF8);
        System.out.println("3DES解密后3：\t" + decodeStr);
        System.out.println("----------------------------------------");
        
        /*
         * AES带秘钥加密解密
         */
        key = bytesToHexString(generatorAESKey(hexStringToBytes(sourceStr)));
        System.out.println("AES秘钥：\t\t" + key);

        encodeBytes = encrypt(sourceStr.getBytes(ENCODING_UTF8), hexStringToBytes(key));
        encodeStr = bytesToHexString(encodeBytes);
        System.out.println("AES加密后1：\t" + encodeStr);
        encodeStr = encryptAESToString(sourceStr, key);
        System.out.println("AES加密后2：\t" + encodeStr);
        encodeStr = encryptAESToString(sourceStr, key, ENCODING_UTF8);
        System.out.println("AES加密后3：\t" + encodeStr);

        decodeBytes = decrypt(encodeBytes, Encryption.hexStringToBytes(key));
        decodeStr = new String(decodeBytes, ENCODING_DEFAULT);
        System.out.println("AES解密后1：\t" + decodeStr);
        decodeStr = decryptAESToString(encodeStr, key);
        System.out.println("AES解密后2：\t" + decodeStr);
        decodeStr = decryptAESToString(encodeStr, key, ENCODING_UTF8);
        System.out.println("AES解密后3：\t" + decodeStr);
        System.out.println("----------------------------------------");
    }

}
